/*
 * ExplorerList.java
 *
 * Created on February 27, 2006, 8:32 PM
 */
package com.bff.slimserver.musicjukebox.ui;

import com.bff.bjj.ui.component.events.KeyTypedEvent;
import com.bff.bjj.ui.component.events.KeyTypedListener;
import com.bff.bjj.ui.component.ColorProperties;
import com.bff.slimserver.musicjukebox.lib.JukeboxProperties;
import com.bff.slimserver.musicjukebox.ui.components.AlbumList;
import com.bff.slimserver.musicjukebox.ui.components.AlbumListCellRenderer;
import com.bff.slimserver.musicjukebox.ui.components.ArtistList;
import com.bff.slimserver.musicjukebox.ui.components.ArtistListCellRenderer;
import com.bff.slimserver.musicjukebox.ui.components.GenreList;
import com.bff.slimserver.musicjukebox.ui.components.GenreListCellRenderer;
import com.bff.bjj.ui.component.BJJPanel;
import com.bff.slimserver.musicjukebox.ui.components.YearList;
import com.bff.slimserver.musicjukebox.ui.components.YearListCellRenderer;
import com.bff.bjj.utils.Utils;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JList;
import javax.swing.JPanel;
import org.bff.slimserver.SlimDatabase;
import org.bff.slimserver.SlimPlaylist;
import org.bff.slimserver.events.DatabaseScanEvent;
import org.bff.slimserver.events.DatabaseScanListener;
import org.bff.slimserver.musicobjects.SlimArtist;
import org.bff.slimserver.musicobjects.SlimGenre;

/**
 *
 * @author  Bill
 */
public class ExplorerListPanel
        extends BJJPanel
        implements ExplorerIface,
        KeyTypedListener,
        DatabaseScanListener {

    private SlimPlaylist playlist;
    private SlimDatabase database;
    private boolean refreshing;
    private int oldSelectedArtistIndex;
    private int oldSelectedAlbumIndex;
    private boolean threadRunning;
    private boolean keyTyped;
    private int oldSelectedYearIndex;
    private int oldSelectedGenreIndex;
    public static int KEY_TIMEOUT = 1000;
    private boolean keyTyping;
    private long lastKeyTime = 0;
    private String cardShowing;
    private boolean filtering;
    private static final String CARD_ARTIST = "CARD_ARTIST";
    private static final String CARD_GENRE = "CARD_GENRE";
    private static final String CARD_YEAR = "CARD_YEAR";
    private static final String VARIOUS_ARTIST = "Various";

    private static final int START_DIVIDER_LOCATION = 400;
    
    public ExplorerListPanel() {
    }

    /** Creates new form ExplorerList */
    public ExplorerListPanel(SlimDatabase database,
            SlimPlaylist playlist) {

        this.database = database;
        this.playlist = playlist;

        initComponents();

        setCardShowing(CARD_ARTIST);

        if (JukeboxProperties.getInstance().isAlbumListArt()) {
            jSplitPane2.setDividerLocation(450);
        } else {
            jSplitPane2.setDividerLocation(450);
        }

        listArtists();

        new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException ex) {
                    Logger.getLogger(ExplorerListPanel.class.getName()).log(Level.SEVERE, null, ex);
                }
                listYears();
                getAlbumJList().setType(AlbumList.ListType.ARTIST);
            }
        }).start();

        new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    Thread.sleep(15000);
                } catch (InterruptedException ex) {
                    Logger.getLogger(ExplorerListPanel.class.getName()).log(Level.SEVERE, null, ex);
                }
                listGenres();
                getAlbumJList().setType(AlbumList.ListType.ARTIST);
            }
        }).start();

        getArtistJList().addKeyTypedListener(this);
        getArtistJList().clearSelection();

        loadProgressBar.setVisible(false);

        JukeboxProperties.getInstance().getSlimMonitor().addDatabaseScanListener(this);

        ((ExplorerButton) btnArtist).setSelectedBackground();

        if(jSplitPane1.getDividerLocation() < START_DIVIDER_LOCATION) {
            jSplitPane1.setDividerLocation(START_DIVIDER_LOCATION);
        }
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        jSplitPane1 = new javax.swing.JSplitPane();
        jPanel3 = new BJJPanel();
        songListTablePanel = new SongListTablePanel();
        jPanel4 = new ExplorerPanel();
        jSplitPane2 = new javax.swing.JSplitPane();
        jPanel2 = new ExplorerPanel();
        spAlbum = new javax.swing.JScrollPane();
        albumList = new AlbumList();
        loadProgressBar = new javax.swing.JProgressBar();
        jPanel7 = new ExplorerPanel();
        jPanel8 = new ExplorerSelectPanel();
        btnArtist = new ExplorerButton();
        btnYear = new ExplorerButton();
        btnGenre = new ExplorerButton();
        btnFilter = new javax.swing.JButton();
        jPanel10 = new javax.swing.JPanel();
        jPanel9 = new ExplorerPanel();
        jPanel1 = new ExplorerPanel();
        spArtist = new javax.swing.JScrollPane();
        artistList = new ArtistList();
        jPanel6 = new ExplorerPanel();
        spGenre = new javax.swing.JScrollPane();
        genreList = new GenreList();
        jPanel5 = new ExplorerPanel();
        spYear = new javax.swing.JScrollPane();
        yearList = new YearList();
        jPanel11 = new ExplorerPanel();
        jPanel11.setVisible(false);
        tfFilter = new javax.swing.JTextField();

        setPreferredSize(new java.awt.Dimension(400, 400));
        setLayout(new java.awt.BorderLayout());

        jPanel3.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1)));
        jPanel3.setPreferredSize(new java.awt.Dimension(200, 200));
        jPanel3.setLayout(new java.awt.BorderLayout());

        songListTablePanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Songs"));
        jPanel3.add(songListTablePanel, java.awt.BorderLayout.CENTER);

        jSplitPane1.setBottomComponent(jPanel3);

        jPanel4.setLayout(new java.awt.BorderLayout());

        jSplitPane2.setDividerLocation(300);
        jSplitPane2.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
        jSplitPane2.setOpaque(false);

        jPanel2.setBorder(javax.swing.BorderFactory.createTitledBorder(null, "Album", javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Tahoma", 0, 11), new java.awt.Color(255, 255, 255))); // NOI18N
        jPanel2.setLayout(new java.awt.BorderLayout());

        albumList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
        albumList.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                albumListMouseClicked(evt);
            }
        });
        albumList.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
            public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
                albumListValueChanged(evt);
            }
        });
        spAlbum.setViewportView(albumList);

        jPanel2.add(spAlbum, java.awt.BorderLayout.CENTER);

        loadProgressBar.setIndeterminate(true);
        loadProgressBar.setString("Loading Albums");
        loadProgressBar.setStringPainted(true);
        jPanel2.add(loadProgressBar, java.awt.BorderLayout.SOUTH);

        jSplitPane2.setRightComponent(jPanel2);

        jPanel7.setLayout(new java.awt.BorderLayout());

        jPanel8.setMaximumSize(new java.awt.Dimension(32767, 28));
        jPanel8.setPreferredSize(new java.awt.Dimension(83, 27));
        jPanel8.setLayout(new java.awt.GridBagLayout());

        btnArtist.setFont(new java.awt.Font("Tahoma", 1, 12));
        btnArtist.setForeground(new java.awt.Color(255, 255, 255));
        btnArtist.setText("Artists");
        btnArtist.setMargin(new java.awt.Insets(0, 0, 0, 0));
        btnArtist.setMaximumSize(new java.awt.Dimension(75, 18));
        btnArtist.setMinimumSize(new java.awt.Dimension(75, 18));
        btnArtist.setPreferredSize(new java.awt.Dimension(75, 18));
        btnArtist.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnArtistActionPerformed(evt);
            }
        });
        jPanel8.add(btnArtist, new java.awt.GridBagConstraints());

        btnYear.setFont(new java.awt.Font("Tahoma", 1, 12));
        btnYear.setForeground(new java.awt.Color(255, 255, 255));
        btnYear.setText("Years");
        btnYear.setMargin(new java.awt.Insets(0, 0, 0, 0));
        btnYear.setMaximumSize(new java.awt.Dimension(75, 18));
        btnYear.setMinimumSize(new java.awt.Dimension(75, 18));
        btnYear.setPreferredSize(new java.awt.Dimension(75, 18));
        btnYear.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnYearActionPerformed(evt);
            }
        });
        jPanel8.add(btnYear, new java.awt.GridBagConstraints());

        btnGenre.setFont(new java.awt.Font("Tahoma", 1, 12));
        btnGenre.setForeground(new java.awt.Color(255, 255, 255));
        btnGenre.setText("Genres");
        btnGenre.setMargin(new java.awt.Insets(0, 0, 0, 0));
        btnGenre.setMaximumSize(new java.awt.Dimension(75, 18));
        btnGenre.setMinimumSize(new java.awt.Dimension(75, 18));
        btnGenre.setPreferredSize(new java.awt.Dimension(75, 18));
        btnGenre.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnGenreActionPerformed(evt);
            }
        });
        jPanel8.add(btnGenre, new java.awt.GridBagConstraints());

        btnFilter.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/slimserver/funnel.png"))); // NOI18N
        btnFilter.setToolTipText("Activate Filter");
        btnFilter.setMaximumSize(new java.awt.Dimension(18, 18));
        btnFilter.setMinimumSize(new java.awt.Dimension(18, 18));
        btnFilter.setPreferredSize(new java.awt.Dimension(18, 18));
        btnFilter.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnFilterActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.insets = new java.awt.Insets(0, 4, 0, 0);
        jPanel8.add(btnFilter, gridBagConstraints);

        jPanel7.add(jPanel8, java.awt.BorderLayout.NORTH);

        jPanel10.setLayout(new java.awt.BorderLayout());

        jPanel9.setLayout(new java.awt.CardLayout());

        jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder(null, "Artist", javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Tahoma", 0, 11), new java.awt.Color(255, 255, 255))); // NOI18N
        jPanel1.setLayout(new java.awt.BorderLayout());

        artistList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
        artistList.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                artistListMouseClicked(evt);
            }
        });
        artistList.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
            public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
                artistListValueChanged(evt);
            }
        });
        spArtist.setViewportView(artistList);

        jPanel1.add(spArtist, java.awt.BorderLayout.CENTER);

        jPanel9.add(jPanel1, "CARD_ARTIST");

        jPanel6.setBorder(javax.swing.BorderFactory.createTitledBorder(null, "Genre", javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Tahoma", 0, 11), new java.awt.Color(255, 255, 255))); // NOI18N
        jPanel6.setMinimumSize(new java.awt.Dimension(200, 59));
        jPanel6.setLayout(new java.awt.BorderLayout());

        genreList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
        genreList.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                genreListMouseClicked(evt);
            }
        });
        genreList.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
            public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
                genreListValueChanged(evt);
            }
        });
        spGenre.setViewportView(genreList);

        jPanel6.add(spGenre, java.awt.BorderLayout.CENTER);

        jPanel9.add(jPanel6, "CARD_GENRE");

        jPanel5.setBorder(javax.swing.BorderFactory.createTitledBorder(null, "Year", javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Tahoma", 0, 11), new java.awt.Color(255, 255, 255))); // NOI18N
        jPanel5.setMinimumSize(new java.awt.Dimension(200, 59));
        jPanel5.setLayout(new java.awt.BorderLayout());

        yearList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
        yearList.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                yearListMouseClicked(evt);
            }
        });
        yearList.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
            public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
                yearListValueChanged(evt);
            }
        });
        spYear.setViewportView(yearList);

        jPanel5.add(spYear, java.awt.BorderLayout.CENTER);

        jPanel9.add(jPanel5, "CARD_YEAR");

        jPanel10.add(jPanel9, java.awt.BorderLayout.CENTER);

        tfFilter.setColumns(20);
        tfFilter.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyTyped(java.awt.event.KeyEvent evt) {
                tfFilterKeyTyped(evt);
            }
        });
        jPanel11.add(tfFilter);

        jPanel10.add(jPanel11, java.awt.BorderLayout.NORTH);

        jPanel7.add(jPanel10, java.awt.BorderLayout.CENTER);

        jSplitPane2.setLeftComponent(jPanel7);

        jPanel4.add(jSplitPane2, java.awt.BorderLayout.CENTER);

        jSplitPane1.setLeftComponent(jPanel4);

        add(jSplitPane1, java.awt.BorderLayout.CENTER);
    }// </editor-fold>//GEN-END:initComponents

    private void albumListValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_albumListValueChanged
        if (getAlbumJList().getSelectedIndex() > -1 && getAlbumJList().getSelectedIndex() != oldSelectedAlbumIndex) {
            if (!isRefreshing()) {
                listSongs();
            }
            oldSelectedAlbumIndex = getAlbumJList().getSelectedIndex();
        }
}//GEN-LAST:event_albumListValueChanged

    private void artistListValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_artistListValueChanged
        loadArtistAlbums();
}//GEN-LAST:event_artistListValueChanged

    private void listYears() {
        getYearJList().listAll();
        getYearJList().clearSelection();
    }

    private void listGenres() {
        getGenreJList().listAll();
        getGenreJList().clearSelection();
    }

    private YearList getYearJList() {
        return (YearList) yearList;
    }

    private GenreList getGenreJList() {
        return (GenreList) genreList;
    }

    private void loadArtistAlbums() {
        loadArtistAlbums(false);
    }

    private void loadArtistAlbums(boolean force) {
        getAlbumJList().setType(AlbumList.ListType.ARTIST);
        if (getArtistJList().getSelectedIndex() != oldSelectedArtistIndex || force) {
            new Thread(new Runnable() {

                @Override
                public void run() {
                    if (!isRefreshing()) {
                        loadProgressBar.setVisible(true);
                        disableComponents();
                        try {
                            if (getArtistJList().getSelectedArtist() == null) {
                                getAlbumJList().clearSelection();
                            } else {
                                getAlbumJList().setArtist(getArtistJList().getSelectedArtist());
                            }
                        } finally {
                            loadProgressBar.setVisible(false);
                            enableComponents();
                        }
                        getAlbumJList().setSelectedIndex(1);
                        listSongs();
                        jPanel2.revalidate();
                    }
                    oldSelectedArtistIndex = getArtistJList().getSelectedIndex();
                }
            }).start();
        }
    }

    private void loadGenreAlbums() {
        loadGenreAlbums(false);
    }

    private void loadGenreAlbums(boolean force) {
        getAlbumJList().setType(AlbumList.ListType.GENRE);
        if (getGenreJList().getSelectedIndex() != oldSelectedGenreIndex || force) {
            new Thread(new Runnable() {

                @Override
                public void run() {
                    if (!isRefreshing()) {
                        loadProgressBar.setVisible(true);
                        disableComponents();
                        try {
                            if (getGenreJList().getSelectedGenre() == null) {
                                getAlbumJList().clearSelection();
                            } else {
                                getAlbumJList().setGenre(getGenreJList().getSelectedGenre());
                                getAlbumJList().setSelectedIndex(1);
                            }
                            jPanel2.revalidate();
                        } finally {
                            loadProgressBar.setVisible(false);
                            enableComponents();
                        }
                        listSongs();
                    }
                    oldSelectedGenreIndex = getGenreJList().getSelectedIndex();
                }
            }).start();
        } else {
            listSongs();
        }
    }

    private void loadYearAlbums() {
        loadYearAlbums(false);
    }

    private void loadYearAlbums(boolean force) {
        getAlbumJList().setType(AlbumList.ListType.YEAR);
        if (getYearJList().getSelectedIndex() != oldSelectedYearIndex || force) {
            new Thread(new Runnable() {

                @Override
                public void run() {
                    if (!isRefreshing()) {
                        loadProgressBar.setVisible(true);
                        disableComponents();
                        try {
                            if (getYearJList().getSelectedYear() == null) {
                                getAlbumJList().clearSelection();
                            } else {
                                getAlbumJList().setYear(getYearJList().getSelectedYear());
                                getAlbumJList().setSelectedIndex(1);
                            }
                            jPanel2.revalidate();
                        } finally {
                            loadProgressBar.setVisible(false);
                            enableComponents();
                        }
                        listSongs();
                    }
                    oldSelectedYearIndex = getYearJList().getSelectedIndex();
                }
            }).start();
        } else {
            listSongs();
        }
    }

    private void showList(String card) {
        CardLayout cl = (CardLayout) jPanel9.getLayout();
        cl.show(jPanel9, card);
        listChanged(card);
    }

    private void yearListValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_yearListValueChanged
        loadYearAlbums();

}//GEN-LAST:event_yearListValueChanged

    private void genreListValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_genreListValueChanged
        loadGenreAlbums();
}//GEN-LAST:event_genreListValueChanged

    private void artistListMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_artistListMouseClicked
        if (evt.getClickCount() == 2) {
        } else {
            JList lstCust = (JList) evt.getSource();
            int currIndex = lstCust.locationToIndex(evt.getPoint());
            SlimArtist currData = (SlimArtist) lstCust.getSelectedValue();
            Rectangle itemBounds = lstCust.getCellBounds(currIndex, currIndex);
            Point currPoint = new Point(evt.getX(), evt.getY());
            Component readyComponent = ((ArtistListCellRenderer) lstCust.getCellRenderer()).getListCellRendererComponent(lstCust,
                    currData, currIndex, true, true);
            readyComponent.setSize(itemBounds.width, itemBounds.height);
            Component pressedComponent = null;
            while (readyComponent != pressedComponent) {
                if (pressedComponent != null) {
                    readyComponent = pressedComponent;
                }
                pressedComponent = readyComponent.getComponentAt((int) (currPoint.getX() - itemBounds.getX()),
                        (int) (currPoint.getY() - itemBounds.getY()));

                if (pressedComponent == null) {
                    return;
                }
                currPoint.setLocation(currPoint.getX() - itemBounds.getX(), currPoint.getY() - itemBounds.getY());
                itemBounds = pressedComponent.getBounds();
            }

            if (pressedComponent instanceof JButton) {
                ((JButton) pressedComponent).doClick();
                //System.out.println("Pressed JButton with text " + ((JButton) pressedComponent).getText() + " in row " + currIndex + " of JList");
            }
        }
    }//GEN-LAST:event_artistListMouseClicked

    private void albumListMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_albumListMouseClicked
        if (evt.getClickCount() == 2) {
        } else {
            JList lstCust = (JList) evt.getSource();
            int currIndex = lstCust.locationToIndex(evt.getPoint());
            Object currData = lstCust.getSelectedValue();
            Rectangle itemBounds = lstCust.getCellBounds(currIndex, currIndex);
            Point currPoint = new Point(evt.getX(), evt.getY());
            Component readyComponent = ((AlbumListCellRenderer) lstCust.getCellRenderer()).getListCellRendererComponent(lstCust,
                    currData, currIndex, true, true);
            readyComponent.setSize(itemBounds.width, itemBounds.height);
            Component pressedComponent = null;
            while (readyComponent != pressedComponent) {
                if (pressedComponent != null) {
                    readyComponent = pressedComponent;
                }
                pressedComponent = readyComponent.getComponentAt((int) (currPoint.getX() - itemBounds.getX()),
                        (int) (currPoint.getY() - itemBounds.getY()));

                if (pressedComponent == null) {
                    return;
                }
                currPoint.setLocation(currPoint.getX() - itemBounds.getX(), currPoint.getY() - itemBounds.getY());
                itemBounds = pressedComponent.getBounds();
            }

            if (pressedComponent instanceof JButton) {
                ((JButton) pressedComponent).doClick();
                //System.out.println("Pressed JButton with text " + ((JButton) pressedComponent).getText() + " in row " + currIndex + " of JList");
            }
        }
    }//GEN-LAST:event_albumListMouseClicked

    private void yearListMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_yearListMouseClicked
        if (evt.getClickCount() == 2) {
        } else {
            JList lstCust = (JList) evt.getSource();
            int currIndex = lstCust.locationToIndex(evt.getPoint());
            String currData = (String) lstCust.getSelectedValue();
            Rectangle itemBounds = lstCust.getCellBounds(currIndex, currIndex);
            Point currPoint = new Point(evt.getX(), evt.getY());
            Component readyComponent = ((YearListCellRenderer) lstCust.getCellRenderer()).getListCellRendererComponent(lstCust,
                    currData, currIndex, true, true);
            readyComponent.setSize(itemBounds.width, itemBounds.height);
            Component pressedComponent = null;
            while (readyComponent != pressedComponent) {
                if (pressedComponent != null) {
                    readyComponent = pressedComponent;
                }
                pressedComponent = readyComponent.getComponentAt((int) (currPoint.getX() - itemBounds.getX()),
                        (int) (currPoint.getY() - itemBounds.getY()));

                if (pressedComponent == null) {
                    return;
                }
                currPoint.setLocation(currPoint.getX() - itemBounds.getX(), currPoint.getY() - itemBounds.getY());
                itemBounds = pressedComponent.getBounds();
            }

            if (pressedComponent instanceof JButton) {
                ((JButton) pressedComponent).doClick();
                //System.out.println("Pressed JButton with text " + ((JButton) pressedComponent).getText() + " in row " + currIndex + " of JList");
            }
        }
    }//GEN-LAST:event_yearListMouseClicked

    private void genreListMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_genreListMouseClicked
        if (evt.getClickCount() == 2) {
        } else {
            JList lstCust = (JList) evt.getSource();
            int currIndex = lstCust.locationToIndex(evt.getPoint());
            SlimGenre currData = (SlimGenre) lstCust.getSelectedValue();
            Rectangle itemBounds = lstCust.getCellBounds(currIndex, currIndex);
            Point currPoint = new Point(evt.getX(), evt.getY());
            Component readyComponent = ((GenreListCellRenderer) lstCust.getCellRenderer()).getListCellRendererComponent(lstCust,
                    currData, currIndex, true, true);
            readyComponent.setSize(itemBounds.width, itemBounds.height);
            Component pressedComponent = null;
            while (readyComponent != pressedComponent) {
                if (pressedComponent != null) {
                    readyComponent = pressedComponent;
                }
                pressedComponent = readyComponent.getComponentAt((int) (currPoint.getX() - itemBounds.getX()),
                        (int) (currPoint.getY() - itemBounds.getY()));

                if (pressedComponent == null) {
                    return;
                }
                currPoint.setLocation(currPoint.getX() - itemBounds.getX(), currPoint.getY() - itemBounds.getY());
                itemBounds = pressedComponent.getBounds();
            }

            if (pressedComponent instanceof JButton) {
                ((JButton) pressedComponent).doClick();
                //System.out.println("Pressed JButton with text " + ((JButton) pressedComponent).getText() + " in row " + currIndex + " of JList");
            }
        }
    }//GEN-LAST:event_genreListMouseClicked

    private void btnArtistActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnArtistActionPerformed
        ((ExplorerButton) btnArtist).setSelectedBackground();
        ((ExplorerButton) btnGenre).setUnselectedBackground();
        ((ExplorerButton) btnYear).setUnselectedBackground();
        showList(CARD_ARTIST);
}//GEN-LAST:event_btnArtistActionPerformed

    private void btnYearActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnYearActionPerformed
        ((ExplorerButton) btnArtist).setUnselectedBackground();
        ((ExplorerButton) btnGenre).setUnselectedBackground();
        ((ExplorerButton) btnYear).setSelectedBackground();
        showList(CARD_YEAR);
}//GEN-LAST:event_btnYearActionPerformed

    private void btnGenreActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnGenreActionPerformed
        ((ExplorerButton) btnArtist).setUnselectedBackground();
        ((ExplorerButton) btnGenre).setSelectedBackground();
        ((ExplorerButton) btnYear).setUnselectedBackground();
        showList(CARD_GENRE);
}//GEN-LAST:event_btnGenreActionPerformed

    private void btnFilterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnFilterActionPerformed
        if (jPanel11.isVisible()) {
            jPanel11.setToolTipText("Activate Filter");
            if (!"".equals(tfFilter.getText())) {
                tfFilter.setText("");
            }
            setFiltering(false);

            final SplashScreen sp = new SplashScreen(Utils.getParentComponent(this), false);
            sp.setIndeterminate(true);
            sp.setTitleLabel("Loading");
            sp.setMainTextArea("\nLoading list.\n\n");
            sp.setProgressBarLabel("Loading...");
            sp.pack();
            new Thread(new Runnable() {

                @Override
                public void run() {
                    setRefreshing(true);
                    try {
                        getAlbumJList().clear();
                        getArtistJList().clearFilter();
                        getGenreJList().clearFilter();
                        getYearJList().clearFilter();
                        jPanel11.setVisible(false);
                    } finally {
                        setRefreshing(false);
                        sp.setStopped(true);
                    }
                }
            }).start();
        } else {
            jPanel11.setVisible(true);
            jPanel11.setToolTipText("Deactivate Filter");
            tfFilter.requestFocus();
        }
    }//GEN-LAST:event_btnFilterActionPerformed

    private void tfFilterKeyTyped(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_tfFilterKeyTyped
        setLastKeyTime(System.currentTimeMillis());
        if (!isKeyTyping()) {
            setKeyTyping(true);
            new Thread(new FilterTimeThread()).start();
        }
    }//GEN-LAST:event_tfFilterKeyTyped
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JList albumList;
    private javax.swing.JList artistList;
    private javax.swing.JButton btnArtist;
    private javax.swing.JButton btnFilter;
    private javax.swing.JButton btnGenre;
    private javax.swing.JButton btnYear;
    private javax.swing.JList genreList;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel10;
    private javax.swing.JPanel jPanel11;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JPanel jPanel4;
    private javax.swing.JPanel jPanel5;
    private javax.swing.JPanel jPanel6;
    private javax.swing.JPanel jPanel7;
    private javax.swing.JPanel jPanel8;
    private javax.swing.JPanel jPanel9;
    private javax.swing.JSplitPane jSplitPane1;
    private javax.swing.JSplitPane jSplitPane2;
    private javax.swing.JProgressBar loadProgressBar;
    private javax.swing.JPanel songListTablePanel;
    private javax.swing.JScrollPane spAlbum;
    private javax.swing.JScrollPane spArtist;
    private javax.swing.JScrollPane spGenre;
    private javax.swing.JScrollPane spYear;
    private javax.swing.JTextField tfFilter;
    private javax.swing.JList yearList;
    // End of variables declaration//GEN-END:variables

    @Override
    public void refreshComponents() {
        setRefreshing(true);
        listArtists();
        listYears();
        listGenres();
        setRefreshing(false);
    }

    private synchronized void listSongs() {
        while (isThreadRunning()) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException ex) {
                Logger.getLogger(ExplorerListPanel.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        new ListSongThread().start();
    }

    public boolean isRefreshing() {
        return refreshing;
    }

    public void setRefreshing(boolean refreshing) {
        this.refreshing = refreshing;
    }

    private void listArtists() {
        getArtistJList().listAll();
    }

    public SlimDatabase getDatabase() {
        return database;
    }

    public void setDatabase(SlimDatabase database) {
        this.database = database;
    }

    public SlimPlaylist getPlaylist() {
        return playlist;
    }

    public void setPlaylist(SlimPlaylist playlist) {
        this.playlist = playlist;
    }

    private AlbumList getAlbumJList() {
        return (AlbumList) albumList;
    }

    private ArtistList getArtistJList() {
        return (ArtistList) artistList;
    }

    private SongListTablePanel getSongListTablePanel() {
        return (SongListTablePanel) songListTablePanel;
    }

    public boolean isThreadRunning() {
        return threadRunning;
    }

    public void setThreadRunning(boolean threadRunning) {
        this.threadRunning = threadRunning;
    }

    public boolean isKeyTyped() {
        return keyTyped;
    }

    public void setKeyTyped(boolean keyTyped) {
        this.keyTyped = keyTyped;
    }

    private SongListTablePanel getSongListPanel() {
        return (SongListTablePanel) songListTablePanel;
    }

    public void listChanged(String list) {
        setCardShowing(list);
        tfFilter.setText("");
        if (CARD_ARTIST.equalsIgnoreCase(list)) {
            int oldIndex = artistList.getSelectedIndex();

            if (oldIndex == -1) {
                oldIndex = 0;
            }

            artistList.setSelectedIndex(-1);
            artistList.setSelectedIndex(oldIndex);
            loadArtistAlbums(true);
        } else if (CARD_YEAR.equalsIgnoreCase(list)) {
            int oldIndex = yearList.getSelectedIndex();

            if (oldIndex == -1) {
                oldIndex = 0;
            }

            yearList.setSelectedIndex(-1);
            yearList.setSelectedIndex(oldIndex);
            loadYearAlbums(true);
        } else {
            int oldIndex = genreList.getSelectedIndex();

            if (oldIndex == -1) {
                oldIndex = 0;
            }

            genreList.setSelectedIndex(-1);
            genreList.setSelectedIndex(oldIndex);

            loadGenreAlbums(true);
        }
    }

    /**
     * @return the keyTyping
     */
    public boolean isKeyTyping() {
        return keyTyping;
    }

    /**
     * @param keyTyping the keyTyping to set
     */
    public void setKeyTyping(boolean keyTyping) {
        this.keyTyping = keyTyping;
    }

    /**
     * @return the lastKeyTime
     */
    public long getLastKeyTime() {
        return lastKeyTime;
    }

    /**
     * @param lastKeyTime the lastKeyTime to set
     */
    public void setLastKeyTime(long lastKeyTime) {
        this.lastKeyTime = lastKeyTime;
    }

    /**
     * @return the cardShowing
     */
    public String getCardShowing() {
        return cardShowing;
    }

    /**
     * @param cardShowing the cardShowing to set
     */
    public void setCardShowing(String cardShowing) {
        this.cardShowing = cardShowing;
    }

    /**
     * @return the filtering
     */
    public boolean isFiltering() {
        return filtering;
    }

    /**
     * @param filtering the filtering to set
     */
    public void setFiltering(boolean filtering) {
        this.filtering = filtering;
    }

    private class ListSongThread extends Thread {

        ListSongThread() {
        }

        @Override
        public void run() {
            setThreadRunning(true);
            try {
                if (!isKeyTyped()) {
                    getSongListPanel().setProgressBarVisible(true);
                    disableComponents();
                    try {
                        if (albumList.getSelectedIndex() > -1) {
                            if (albumList.getSelectedIndex() == 0) {
                                switch (((AlbumList) albumList).getType()) {
                                    case ARTIST:
                                        if (getArtistJList().getSelectedArtist().getName().equalsIgnoreCase(VARIOUS_ARTIST)) {
                                            getSongListTablePanel().setVariousArtist(getArtistJList().getSelectedArtist());
                                        } else {
                                            getSongListTablePanel().setArtist(getArtistJList().getSelectedArtist());
                                        }
                                        break;
                                    case YEAR:
                                        getSongListTablePanel().setYear(getYearJList().getSelectedYear());
                                        break;
                                    case GENRE:
                                        getSongListTablePanel().setGenre(getGenreJList().getSelectedGenre());
                                        break;
                                }
                                getSongListTablePanel().setAlbum(null);

                            } else {
                                if (getSongListTablePanel().getAlbum() == null
                                        || !getSongListTablePanel().getAlbum().equals(getAlbumJList().getSelectedAlbum())) {
                                    if (getArtistJList().getSelectedArtist().getName().toUpperCase().startsWith(VARIOUS_ARTIST.toUpperCase())) {
                                        getSongListTablePanel().setVariousAlbum(getAlbumJList().getSelectedAlbum());
                                    } else {
                                        getSongListTablePanel().setAlbum(getAlbumJList().getSelectedAlbum());
                                    }
                                }
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        getSongListPanel().setProgressBarVisible(false);
                        enableComponents();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            setThreadRunning(false);
        }
    }

    private void disableComponents() {
        setComponentAbility(false);
    }

    private void enableComponents() {
        setComponentAbility(true);

        if (isFiltering()) {
            tfFilter.requestFocus();
        }
    }

    private void setComponentAbility(boolean b) {
        spAlbum.setEnabled(b);
        albumList.setEnabled(b);
        artistList.setEnabled(b);
        yearList.setEnabled(b);
        genreList.setEnabled(b);
        btnArtist.setEnabled(b);
        btnYear.setEnabled(b);
        btnGenre.setEnabled(b);
        tfFilter.setEnabled(b);
    }

    @Override
    public void keyTyped(KeyTypedEvent event) {
        switch (event.getId()) {
            case TYPE_STARTED:
                setKeyTyped(true);
                break;
            default:
                setKeyTyped(false);
                if (event.isChange()) {
                    listSongs();
                }
                break;
        }
    }

    @Override
    public void databaseScanEventReceived(DatabaseScanEvent event) {
        if (event.getId() == DatabaseScanEvent.SCAN_ENDED) {
            final SplashScreen sp = new SplashScreen(Utils.getParentComponent(this), true);

            sp.setIndeterminate(true);
            sp.setTitleLabel("Reloading");
            sp.setMainTextArea("\nReloading Artists after database scan.\n\n");
            sp.setProgressBarLabel("Reloading...");
            sp.pack();

            Thread t = new Thread(new Runnable() {

                @Override
                public void run() {
                    try {
                        getArtistJList().listAll();
                    } finally {
                        sp.setStopped(true);
                    }
                }
            });
            t.start();

        }
    }

    private class ExplorerSelectPanel extends JPanel {

        private Image image;

        public ExplorerSelectPanel() {
            try {
                image = ImageIO.read(ExplorerButton.class.getResourceAsStream("/resources/slimserver/explorer_button_panel_background.png"));
            } catch (IOException ex) {
                Logger.getLogger(ExplorerListPanel.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(image, 0, 0, this);
        }
    }

    private class ExplorerButton extends JButton {

        private Image image;
        private Image unSelectedimage;
        private Image selectedImage;

        public ExplorerButton() {
            try {
                unSelectedimage = ImageIO.read(ExplorerButton.class.getResourceAsStream("/resources/slimserver/explorer_button_background.png"));
                selectedImage = ImageIO.read(ExplorerButton.class.getResourceAsStream("/resources/slimserver/explorer_button_selected_background.png"));
            } catch (IOException ex) {
                Logger.getLogger(ExplorerListPanel.class.getName()).log(Level.SEVERE, null, ex);
            }
            setContentAreaFilled(false);
            setUnselectedBackground();
            setBorder(BorderFactory.createEtchedBorder(Color.GRAY, Color.GRAY));
        }

        @Override
        public void paintComponent(Graphics g) {
            g.drawImage(image, 0, 0, this);
            super.paintComponent(g);
        }

        public void setSelectedBackground() {
            image = selectedImage;
            repaint();
        }

        public void setUnselectedBackground() {
            image = unSelectedimage;
            repaint();
        }
    }

    private class ExplorerPanel extends JPanel {

        public ExplorerPanel() {
            setBackground(ColorProperties.PANEL_COVER_ART_BACKGROUND);
        }
    }

    private class FilterTimeThread implements Runnable {

        @Override
        public void run() {
            while (true) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException ex) {
                    Logger.getLogger(ArtistList.class.getName()).log(Level.SEVERE, null, ex);
                }

                if (getLastKeyTime() + KEY_TIMEOUT < System.currentTimeMillis()) {
                    setKeyTyping(false);
                    break;
                }
            }

            setFiltering(true);

            if (CARD_ARTIST.equalsIgnoreCase(getCardShowing())) {
                getArtistJList().filterList(tfFilter.getText().trim());
            } else if (CARD_YEAR.equalsIgnoreCase(getCardShowing())) {
                getYearJList().filterList(tfFilter.getText().trim());
            } else {
                getGenreJList().filterList(tfFilter.getText().trim());
            }
        }
    }
}
